﻿using System;
using System.IO;
using System.Reflection;

using ICSharpCode.SharpZipLib.Zip;
using Orchard.FileSystems.Media;
using EDB.SmoothStreaming.Models;

namespace EDB.SmoothStreaming.Services {
    public class VideoService : IVideoService {
        private readonly IStorageProvider _storageProvider;
        private readonly IGacService _gacService;

        static VideoService() {
            AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve);
        }

        static Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args) {
            if (args.Name.StartsWith("EDB.SmoothStreaming,"))
                return Assembly.GetExecutingAssembly();
            else
                return null;
        }

        public VideoService(IStorageProvider storageProvider, IGacService gacService) {
            _storageProvider = storageProvider;
            _gacService = gacService;
        }

        public string SaveStreamToFile(string filePath, Stream inputStream) {
            var file = _storageProvider.CreateFile(filePath);
            var outputStream = file.OpenWrite();
            var buffer = new byte[8192];
            for (; ; ) {

                var length = inputStream.Read(buffer, 0, buffer.Length);
                if (length <= 0)
                    break;
                outputStream.Write(buffer, 0, length);
            }
            outputStream.Dispose();
            return filePath;
        }
        public bool Encode(string sourcePath, string destinationPath, VideoPart part) {
            bool result = false;

            // Not the best way to load the assembly, need to find a better way to do it.
            string assemblyPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Modules\\EDB.SmoothStreaming\\Content\\EDB.SmoothStreaming.Encoder.dll");
            Assembly assembly = Assembly.LoadFrom(assemblyPath);
            Type type = assembly.GetType("EDB.SmoothStreaming.Encoder.Encoder");
            IEncoder encoder = Activator.CreateInstance(type) as IEncoder;
            result = encoder.Encode(sourcePath, destinationPath, part);

            return result;
        }

        public void UnzipMediaFileArchive(string targetFolder, string filePath) {
            using (var fileStream = new FileStream(filePath, FileMode.OpenOrCreate, FileAccess.Read, FileShare.None)) {
                var fileInflater = new ZipInputStream(fileStream);
                ZipEntry entry;
                while ((entry = fileInflater.GetNextEntry()) != null) {

                    if (!entry.IsDirectory && entry.Name.Length > 0) {
                        var entryName = Path.Combine(targetFolder, entry.Name);
                        var directoryName = Path.GetDirectoryName(entryName);

                        _storageProvider.TryCreateFolder(directoryName);
                        SaveStreamToFile(entryName, fileInflater);
                    }
                }
            }
        }

        public bool CheckForExpressionEncoder() {
            bool result = true;
            try {
                // Is there a better way to check for non-specific version of an assembly in the GAC?
                _gacService.QueryAssemblyInfo("Microsoft.Expression.Encoder");
                _gacService.QueryAssemblyInfo("Microsoft.Expression.Encoder.Types");
                _gacService.QueryAssemblyInfo("Microsoft.Expression.Encoder.Utilities");
            }
            catch {
                result = false;
            }
            return result;
        }
    }
}